package com.hly.musicbackground.model.boots.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hly.musicbackground.Enum.SortEnum;
import com.hly.musicbackground.Enum.UserLogEnum;
import com.hly.musicbackground.Final.FictionFinal;
import com.hly.musicbackground.Final.FictionShelfFinal;
import com.hly.musicbackground.Final.RedisFinal;
import com.hly.musicbackground.Final.SearchFinal;
import com.hly.musicbackground.Utils.*;
import com.hly.musicbackground.dao.FictionDao;
import com.hly.musicbackground.domain.*;
import com.hly.musicbackground.model.boots.VO.*;
import com.hly.musicbackground.model.boots.params.FictionQueryParams;
import com.hly.musicbackground.model.boots.service.*;
import com.hly.musicbackground.model.user.service.UserLogService;
import com.hly.musicbackground.result.Code;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Log4j2
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FictionServiceImpl extends ServiceImpl<FictionDao, Fiction> implements FictionService {

    private final FictionClassService fictionClassService;
    private final FictionChapterService fictionChapterService;
    private final FictionShelfService fictionShelfService;
    private final FictionContentService fictionContentService;
    private final RedisUtil redisUtil;
    private final UserLogService userLogService;
    private final DozerUtils dozerUtils;
    private final FictionDocumentWwwFyhuaboCom fictionDocument;

    private final int fictionContentNum = 2500;

    @Override
    public FictionListVO searchListDom(String key) {
        Document doc = JsoupBooksUtil.getDoc(SearchFinal.BOOKS_SEARCH + key);
        List<Fiction> fictions = searchDomToObject(doc);
        fictions.forEach(n -> {
            if (n.getFictionId() != 0 || n.getWordNum() == 0){
                n.setWordNum((int) (fictionChapterService.getFictionChapterCount(n.getFictionId()) * fictionContentNum));
            }
        });
        saveOrUpdateBatch(fictions);
        FictionListVO fictionListVO = new FictionListVO();
        fictionListVO.setList(fictions);
        fictionListVO.setTotal(fictions.size());
        return fictionListVO;
    }

    @Override
    public List<Fiction> searchDomToObject(Document document) {
        return fictionDocument.searchDomToObject(document);
    }


    @Override
    public Fiction DocumentToFictionDetail(Document document){
        return fictionDocument.DocumentToFictionDetail(document);
    }

    @Override
    public FictionDetailVO getFictionDetail(int id, int uid) {
        Fiction byId = getById(id);
        if (byId == null){
            Code.BUSINESS_ERR("该小说不存在");
        }

        FictionDetailVO fictionDetailVO = new FictionDetailVO();

        fictionDetailVO.setFiction(byId);


        // 同类小说
        fictionDetailVO.setSimilarFiction
                (fictionQueryList(FictionQueryParams
                        .builder()
                        .limit(8)
                        .isRandom(true)
                        .fictionClassId(byId.getFictionClassId()).build()).getList());

        // 判断是否加入书架
        fictionDetailVO.setIsBookshelf(fictionShelfService
                .isBookshelf(uid, id, FictionShelfFinal.FICTION_SHELF));

        // 获取小说目录
        List<FictionChapter> fictionChapters = fictionChapterService.
                getAutoFictionChapterList(byId);

        // 小说目录不为空
        if (fictionChapters.size() != 0){
            fictionDetailVO.setFictionChapters(fictionChapters);

            // 开启一个线程加载小说所有内容
//            ThreadPoolUtils.start(() -> {
//                paquContent(byId, fictionChapters);
//            });

            // 获取第一章小说内容
            fictionDetailVO.setContent(fictionContentService.
                    getFictionContent(fictionChapters.get(0)));


            int fictionChapterId = fictionChapters.get(0).getFictionChapterId();
            if(fictionDetailVO.getIsBookshelf()){
                fictionChapterId = 0;
            }

            // 添加历史记录
            fictionShelfService.saveOrUpdateFictionShelfType(id, uid,
                    FictionShelfFinal.FOOT, fictionChapterId,
                    fictionChapters.get(0)
                            .getChapterNum());

        }else {
            fictionShelfService.saveOrUpdateFictionShelfType(id, uid,
                    FictionShelfFinal.FOOT, -1, -1);
        }

        int[] fictionShelfNum = fictionShelfService.getFictionShelfNumArras(id);

        byId.setBrowse(byId.getBrowse() + 1);
        byId.setBookshelf(fictionShelfNum[1]);

        updateById(byId);

        userLogService.addUserLogOrFail(byId.getFictionId(), UserLogEnum.GET_FICTION_DETAIL, byId.getFictionName());

        return fictionDetailVO;
    }

//    public List<Fiction> getQueryRandomFiction(RandomFictionQuery query) {
//        QueryWrapper<Fiction> wrapper = new QueryWrapper<>();
//        wrapper.lambda()
//                .eq(Fiction::getAbnormal, FictionFinal.abnormal_ok)
//                .eq(query.getFictionClassId() != 0,
//                 Fiction::getFictionClassId, query.getFictionClassId());
//
//        long cont = count(wrapper);
//        int length = (int) cont;
//        int i = 0;
//
//        if (length > query.getLimit()){
//            Random random = new Random();
//            i = random.nextInt(length < query.getLimit() ? 0 : length - query.getLimit());
//        }
//
//        wrapper.last("limit " + i + ", " + query.getLimit());
//        return baseMapper.selectList(wrapper);
//    }

//    @Override
//    public FictionShelfListVO getFictionShelfListVO(int userId, String type, int page, int limit) {
//        FictionShelfListVO fictionShelfListVO = new FictionShelfListVO();
//        List<FictionShelfVO> list = fictionShelfService.getFictionShelfVOs(userId, type, page, limit);
//
//        /**
//         * 如果是书架中的小说，获取最新章节信息
//         * */
//        list.stream().forEach(n -> {
//            if (FictionShelfFinal.FICTION_SHELF.equals(n.getType())){
//                FictionChapter fictionChapter = fictionChapterService.getNewChapter(n.getFictionId());
//                n.setNewChapterName(fictionChapter.getChapterName());
//
//                //有当前章节的情况，获取当前章节名称
//                if (n.getFictionChapterId() != -1){
//                    n.setChapterName(fictionChapterService.getById(n.
//                            getFictionChapterId()).getChapterName());
//                }
//
//                // 统计有多少小说更新了
//                if (n.getNewChapter() == 1){
//                    fictionShelfListVO.setNewFictionNum(
//                            fictionShelfListVO.getNewFictionNum() + 1);
//                }
//            }
//            int length = fictionChapterService.getChapterLength(n.getFictionId());
//            n.setChapterLength(length);
//        });
//
//        fictionShelfListVO.setList(list);
//        return fictionShelfListVO;
//    }

    @Override
    public FictionShelfListVO getFictionShelfListVO(int userId, String type, int page, int limit) {
        FictionShelfListVO fictionShelfListVO = new FictionShelfListVO();

        List<FictionShelfVO> list = dozerUtils.convert(fictionShelfService.lambdaQuery()
                .eq(!"all".equals(type), FictionShelf::getType, type)
                .eq(FictionShelf::getUserId, userId)
                .orderByDesc(FictionShelf::getUpdateTime)
                .page(new Page<>(page, limit)).getRecords(), FictionShelfVO.class);

        fictionShelfListVO.setList(list);

        list.forEach(n -> {
            // 获取小说信息
            Fiction byId = getById(n.getFictionId());
            n.setFictionName(byId.getFictionName());
            n.setFictionAuthor(byId.getFictionAuthor());
            n.setImage(byId.getImage());
            n.setNewChapterTime(byId.getUpdateTime());
        });

        // 如果不是书架则直接返回
        if (!FictionShelfFinal.FICTION_SHELF.equals(type)) {
            return fictionShelfListVO;
        }

        /**
         * 如果是书架中的小说，获取最新章节信息
         * */
        list.stream().forEach(n -> {

            // 获取小说最新章节名称
            FictionChapter fictionChapter = fictionChapterService.getNewChapter(n.getFictionId());
            n.setNewChapterName(fictionChapter.getChapterName());

            // 有当前章节的情况，获取当前章节名称
            if (n.getFictionChapterId() != -1){
                n.setChapterName(fictionChapterService.getById(n.
                        getFictionChapterId()).getChapterName());
            }

            // 统计有多少小说更新了
            if (n.getNewChapter() == 1){
                fictionShelfListVO.setNewFictionNum(
                        fictionShelfListVO.getNewFictionNum() + 1);
            }

            int length = fictionChapterService.getChapterLength(n.getFictionId());
            n.setChapterLength(length);
        });

        return fictionShelfListVO;
    }

    @Scheduled(cron = "0 0 12 * * ?")
    public void timingInspectUpdateFiction() {
        log.info("-----------------------开始检查书籍更新-----------------------------");
        List<Integer> ids = fictionShelfService.getFictionIds
                (FictionShelfFinal.FICTION_SHELF, 0);
        // 检查小说更新
        InspectUpdateFiction(ids);
        log.info("-----------------------检查书籍更新完成-----------------------------");
    }

    @Override
    public int InspectUpdateFiction(List<Integer> ids) {

        //需要更新信息的小说
        ArrayList<Fiction> fictions = new ArrayList<>();

        //根据小说id获取小说信息集合
        List<Fiction> list = lambdaQuery().in(Fiction::getFictionId, ids).list();

        list.stream().forEach(f -> {

            // 尝试获取锁，若获取失败则暂不更新，保证了60秒类同一本小说不要重复更新
            if(redisUtil.tryLock(RedisFinal.UPDATE_FICTION_CHAPTER_KEY + f.getFictionId(), 60L)){

                //获取小说信息和目录
                Document doc = JsoupBooksUtil.getDoc(f.getFictionLink());

                //解析目录并检查是否有更新，更新了将目录保存到数据库
                boolean b = fictionChapterService.DocumentToObjectAndUpdate(doc,
                        f.getFictionId());

                //更新了最新章节，更新小说信息
                if (b){
                    f.setUpdateTime(DocumentToFictionDetail(doc).getUpdateTime());
                    long num = fictionChapterService.getFictionChapterCount(f.getFictionId()) * fictionContentNum;
                    f.setWordNum((int) num);
                    fictions.add(f);
                }

            }

        });

        //将数据保存到数据库
        updateBatchById(fictions);

        return fictions.size();
    }

    @Override
    public boolean UserBookshelfInspectUpdateFiction(int uid) {
        // 获取书架中的小说id
        List<Integer> ids = fictionShelfService.getFictionIds
                (FictionShelfFinal.FICTION_SHELF, uid);
        if (ids.size() == 0){
            Code.BUSINESS_ERR("您还没有书籍！");
        }
        userLogService.addUserLogOrFail(UserLogEnum.BOOKSHELF_INSPECT);
        // 检查更新
        return InspectUpdateFiction(ids) != 0;
    }

    @Override
    public FictionListVO fictionQueryList(FictionQueryParams params) {
        FictionListVO listVO = new FictionListVO();

        QueryWrapper<Fiction> query = new QueryWrapper<>();

        //小说类型id
        query.lambda().eq(params.getFictionClassId() != 0,
                Fiction::getFictionClassId, params.getFictionClassId())

                //小说最小字数
                .gt(params.getMinNumWord() != 0,
                        Fiction::getWordNum, params.getMinNumWord())

                //小说最大字数
                .lt(params.getMaxNumWord() != 0,
                        Fiction::getWordNum, params.getMaxNumWord())

                //最小更新时间
                .gt(params.getMinTime() != null,
                        Fiction::getUpdateTime, params.getMinTime())

                //最大更新时间
                .lt(params.getMaxTime() != null,
                        Fiction::getUpdateTime, params.getMaxTime())

                //是否完结
                .eq(params.getIsEnd() != 0,
                        Fiction::getStatus, params.getIsEnd());

        //搜索关键字
        if (StringUtils.isNotEmpty(params.getKey())){
            query.lambda().and(n -> {
               n.like(Fiction::getFictionName, params.getKey())
               .or()
               .like(Fiction::getFictionAuthor, params.getKey());
            });
        }

        //排序
        if (StringUtils.isNotEmpty(params.getSort())){

            String[] split = params.getSort().split(";");

            for (int i = 0; i < split.length; i++) {
                String[] s = split[i].split(":");
                query.orderBy(true, SortEnum.ASC.getValue().equals(s[1]), s[0]);
            }

        }

        if (params.isRandom()){
            int length = (int) count(query);
            int i = 0;

            if (length > params.getLimit()){
                Random random = new Random();
                i = random.nextInt(length < params.getLimit() ? 0 : length - params.getLimit());
            }

            query.last("limit " + i + ", " + params.getLimit());

            List<Fiction> fictions = baseMapper.selectList(query);
            listVO.setList(fictions);
        }else {
            Page<Fiction> page = baseMapper.selectPage(new Page<>(params.getPage(),
                    params.getLimit()), query);
            listVO.setList(page.getRecords());
            listVO.setTotal((int) page.getTotal());
        }

        return listVO;
    }

    @Override
    public List<FictionQueryDataVO> fictionQueryData() {
        ArrayList<FictionQueryDataVO> fictionQueryDataVOS = new ArrayList<>();

        //分类筛选
        fictionQueryDataVOS.add(FictionQueryDataVO.builder()
                .title("分类")
                .type(FictionFinal.QueryDataTypeClass)
                .list(fictionClassService.list().stream()
                .map(n -> FictionQueryDataItemVO.builder()
                            .title(n.getFictionClassName())
                            .fictionClassId(n.getFictionClassId())
                            .build()
                ).collect(Collectors.toList()))
                .build());

        //字数筛选
        ArrayList<FictionQueryDataItemVO> numList = new ArrayList<>();

        numList.add(FictionQueryDataItemVO.builder()
                .maxNumWord(150000)
                .title("15万以下").build());

        numList.add(FictionQueryDataItemVO.builder()
                .maxNumWord(500000)
                .minNumWord(150000)
                .title("15万至50万").build());

        numList.add(FictionQueryDataItemVO.builder()
                .maxNumWord(1000000)
                .minNumWord(500000)
                .title("50万至100万").build());

        numList.add(FictionQueryDataItemVO.builder()
                .minNumWord(1000000)
                .title("100万以上").build());

        numList.add(FictionQueryDataItemVO.builder()
                .minNumWord(2000000)
                .title("200万以上").build());

        fictionQueryDataVOS.add(FictionQueryDataVO.builder()
                .title("字数")
                .list(numList)
                .type(FictionFinal.QueryDataTypeWord)
        .build());

        //最近更新时间
        ArrayList<FictionQueryDataItemVO> timeList = new ArrayList<>();

        timeList.add(FictionQueryDataItemVO.builder()
                .minTime(DateUtils.currentTimeSubtract(259200000))
                .title("3天内").build());

        timeList.add(FictionQueryDataItemVO.builder()
                .minTime(DateUtils.currentTimeSubtract(604800000))
                .title("7天内").build());

        timeList.add(FictionQueryDataItemVO.builder()
                .minTime(DateUtils.currentTimeSubtract(2592000000L))
                .title("30天内").build());

//        fictionQueryDataVOS.add(FictionQueryDataVO.builder()
//                .title("更新")
//                .list(timeList)
//                .type(FictionFinal.QueryDataTypeUpdateTime)
//                .build());


        // 排序
        ArrayList<FictionQueryDataItemVO> sortList = new ArrayList<>();

        sortList.add(FictionQueryDataItemVO.builder()
                .sort("browse:desc;bookshelf:desc;")
                .title("人气最高").build());

        sortList.add(FictionQueryDataItemVO.builder()
                .sort("browse:desc;bookshelf:desc;")
                .title("最近更新").build());

        sortList.add(FictionQueryDataItemVO.builder()
                .sort("bookshelf:desc;")
                .title("收藏最多").build());

        sortList.add(FictionQueryDataItemVO.builder()
                .sort("word_num:desc;")
                .title("字数最多").build());

        fictionQueryDataVOS.add(FictionQueryDataVO.builder()
                .title("排序")
                .list(sortList)
                .type(FictionFinal.QueryDataTypeSort)
                .build());


        //是否完结
        ArrayList<FictionQueryDataItemVO> isEndList = new ArrayList<>();

        isEndList.add(FictionQueryDataItemVO.builder()
                .isEnd(0)
                .title("连载").build());

        isEndList.add(FictionQueryDataItemVO.builder()
                .isEnd(1)
                .title("完结").build());

        fictionQueryDataVOS.add(FictionQueryDataVO.builder()
                .title("状态")
                .list(isEndList)
                .type(FictionFinal.QueryDataTypeStatus)
                .build());

        return fictionQueryDataVOS;
    }

    @Override
    public List<FictionClassVO> getFictionClassList() {

        List<FictionClassVO> list = fictionClassService.list()
        .stream().map(n -> FictionClassVO
            .builder()
                .fictionClassName(n.getFictionClassName())
                .fictionClassId(n.getFictionClassId())
                .image(lambdaQuery()
                .eq(Fiction::getFictionClassId, n.getFictionClassId())
                .orderByDesc(Fiction::getBrowse)
                .page(new Page<Fiction>(1,1)).getRecords().get(0).getImage())
            .build()
        ).collect(Collectors.toList());
        return list;
    }

    @Override
    public void paqu(int i) {
        while (true){
            try {
                Thread.sleep(500);
                Document doc = JsoupBooksUtil.getDoc("http://www.fyhuabo.com/bqg/" + i + "/");
                Fiction fiction = DocumentToFictionDetail(doc);
                Fiction one = lambdaQuery()
                        .eq(Fiction::getFictionName, fiction.getFictionName())
                        .eq(Fiction::getFictionAuthor, fiction.getFictionAuthor()).one();

                if(one != null){
                    one.setImage(fiction.getImage());
                    fiction = one;
                    log.info("=========修改了第" + i + "本小说" + fiction.getFictionName() + "==================");
                }else {
                    save(fiction);
                }
                List<FictionChapter> list = fictionChapterService
                        .DocumentToObject(doc, fiction.getFictionId());
                //for (FictionChapter n : list){
                //    FictionChapter chapter = fictionChapterService.lambdaQuery()
                //            .eq(FictionChapter::getChapterLink, n.getChapterLink()).one();
                //    if (chapter == null){
                //        fictionChapterService.save(n);
                //    }else if (chapter.getFictionId() == 0){
                //        chapter.setFictionId(fiction.getFictionId());
                //        fictionChapterService.updateById(chapter);
                //    }
                //}
                fiction.setWordNum(list.size() * fictionContentNum);
                updateById(fiction);
                //paquContent(fiction, list);
                log.info("=========完成了第" + i + "本小说" + fiction.getFictionName() + "==================");
            }catch (Exception e){
                log.info("=========第" + i + "本小说获取失败==================");
            }finally {
                i++;
            }
        }
    }

    @Override
    public void paquContent(Fiction fiction, List<FictionChapter> fictionChapters) {

        String lock = RedisFinal.FICTION_CONTENTS_KEY + fiction.getFictionId();

        if (!redisUtil.tryLock(lock)){
            return;
        }

        try {

            fiction.setWordNum(0);

            fictionChapters.stream().forEach(n -> {
                try {
                    Thread.sleep(3100);
                }catch (Exception e){}
                FictionContentVO content = fictionContentService.getFictionContent(n);
                log.info("=======完成了第" + fiction.getFictionId() + "本小说" + fiction.getFictionName() + "，的第" + n.getChapterNum() + "章" + n.getChapterName() + "================");
                fiction.setWordNum(fiction.getWordNum()
                        + content.getFictionContent().getNum());
            });
            updateById(fiction);

        }catch (Exception e){
        }finally {
            redisUtil.releaseLock(lock);
        }
    }

}
